package student.productions;

import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import student.State;

/**
 * A representation of the Condition production.
 */
public class Condition extends MutableNode implements EvaluableNode {
	// Invariant for children: children has at least one Conjunction, and only Conjunctions.

	/**
	 * Constructor: creates an instance of Condition whose children are all the Nodes in allChildren.
	 * @param allChildren list of children.
	 * Requires: Contents of allChildren are in form: Conjunction ( Conjunction )*
	 */
	public Condition(List<AbstractNode> allChildren) {
		if(allChildren.size() > 0)
			children= allChildren;
		else
			throw new IllegalArgumentException("There must be at least one child to make this production.");
	}
	

	@Override
	public boolean eval(State s) {
		// TODO Auto-generated method stub
		return false;
	}

	/**
	 * Returns toMutate with one mutation. 
	 * Effects: makes the mutation directly to toMutate
	 * @param toMutate the program to make the change to
	 * @return the mutated version of toMutate
	 * Requires: toMutate is a Rule
	 */
	public static AbstractNode mutate(AbstractNode toMutate, Program genome){
		LinkedList<MutableNode> mutableChildren = new LinkedList<MutableNode>();
		LinkedList<MutableNode> descendants = new LinkedList<MutableNode>();
		for(Node n : toMutate.children)
			mutableChildren.add((MutableNode) n);
		for(MutableNode n : mutableChildren)
			n.addMutableTree(descendants);
		Random rnd = new Random();
		if(descendants.size() != 0){//this will almost certainly never be 0
			int nodeToMutate = rnd.nextInt(descendants.size());//choose the node to mutate out of all of toMutate's descendants
			descendants.get(nodeToMutate).mutate(genome);
		}
		return toMutate;
	}

	@Override
	public void mutate(Program genome) {
		StringBuffer sb = new StringBuffer();
		prettyPrint(sb);
		sb.append("was changed to ");
		Random rnd = new Random();
		int mutationType = rnd.nextInt(2);
		int child = rnd.nextInt(children.size());
		if(children.size() == 1 || mutationType == 0)
			children.set(child, AbstractNode.chooseConjunction(genome, children.get(child)));
		else{
			AbstractNode temporary = children.get(child);
			children.clear();
			children.add(temporary);
		}
		prettyPrint(sb);
		System.out.println(sb);		
	}
	
	@Override
	public void prettyPrint(StringBuffer sb) {
		children.get(0).prettyPrint(sb);
		for(int i = 1; i < children.size(); i++){
			sb.append("\nor ");
			children.get(i).prettyPrint(sb);
		}
	}


	@Override
	public Node duplicate() {
		List<AbstractNode> duplicateChildren= new LinkedList<AbstractNode>();
		for (AbstractNode n : children) {
			duplicateChildren.add((AbstractNode)n.duplicate());
		}
		return new Condition(duplicateChildren);
	}

}
